package momo.pagri.util;

import org.apache.commons.math.MathException;
import org.apache.commons.math.distribution.AbstractIntegerDistribution;
import org.apache.commons.math.distribution.IntegerDistribution;

public class ZipfDistribution extends AbstractIntegerDistribution implements
		IntegerDistribution {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private double s;
	
	private double n;
	
	
	private double harmonicNum(double k, double s) {
		double value = 0;
		for (int i = 1; i <= k; i++) {
			double pow = Math.pow(i, s);
			value += 1.0 / pow;
		}
		return value;
	}
	
	public ZipfDistribution(double s, double n) {
		super();
		this.s = s;
		this.n = n;
	}

	@Override
	public double cumulativeProbability(int k) throws MathException {
		if ((k < 1) || (k > n))
			return 0;
		return harmonicNum(k,s) / harmonicNum(n, s);
	}

	@Override
	protected int getDomainLowerBound(double p) {
		int k = 1;
		try {
			while (cumulativeProbability(k) < p)
				k++;
		} catch (MathException e) {
			assert false;
			e.printStackTrace();
		}
		return k-1;
	}

	@Override
	protected int getDomainUpperBound(double p) {
		int k = 1;
		try {
			while (cumulativeProbability(k) < p)
				k++;
		} catch (MathException e) {
			assert false;
			e.printStackTrace();
		}
		return k;
	}

	@Override
	public double probability(int k) {
		if ((k < 1) || (k > n))
			return 0;
		double hn = harmonicNum(n, s);
		double pow = (double) Math.pow(k, s);
		return ( ( 1.0 / ( pow ) ) / hn );
	}

}
